screeclayproggramingfandomcom-20200214-history
Unity3D Building Damage Tutorial- Part XII - Classes architecture modification
Old Classes As for now, we have two custom Classes for our damage model: ''MeshManager ''and ''Verticle. ''MeshManager is placed in other class, in this case ''Building, ''but it may be in other class. Current way it is done may work with single mesh objects, but what with more complex prefabs? Also, it would be better to "control" the damage not via code, but with adding new "components" in editor view and editing its properties. This would allow setting some parts of prefab as not flamable and other flamable to some point. New Classes As visible on the new scheme, there are some new and some old Classes. #GeneralFireDamageMenager -> It should be added as script in "root" of each prefab. It inherits from MonoBehaviour, so have Start, Update Awake etc. methods. It serves as a "mediator" between Damage Model and Programer and between MeshManagers itself. Also sets properties of meshManagers by taking them from FireDamageProperties. Finally, finds inter-mesh connections. (in fact inter-MeshManagers) #FireDamageProperties -> Class added in editor to each mesh as scripts. It stores parameters with which MeshManagers will work. These are set by programmer in editor before game starts. Moreover, this class stores the MeshFilter which is its "sibling" component. #MeshManager -> Like last time, but now communicates with GeneralFireDamageMenager instead of Building class. #Verticles -> Like before GeneralFireDamageMenager class using UnityEngine; using System; // For Exceprion using System.Collections; using System.Collections.Generic; using System.Linq; //for finding min() and max() in dictionary using RTS; namespace RTS{ /// /// A class that manages communication between meshes. /// All Updates and future multi-threading will be held here /// It is only point where mesh-programmer communication will take place! /// public class GeneralFireDamageManager : MonoBehaviour{ private List meshManagers = new List(); List InterMeshPairsList; //a list of pairs FireDamageProperties[] myFireDamageProperties; private void Start(){ List myMeshFilters = new List(); InterMeshPairsList = new List(); List myMeshManagerProperties = new List(); myFireDamageProperties = GetComponentsInChildren() as FireDamageProperties[];// foreach(FireDamageProperties props in myFireDamageProperties){ try{// I am trying as there may be no meshFilter as a "siblins" of FDP. Somebody made an error and now a exception will be thrown MeshFilter CurrentFilter; CurrentFilter = props.ReturnMeshFilter(); myMeshFilters.Add(CurrentFilter); myMeshManagerProperties.Add( props.ReturnMeshManagerProperties() ); }catch(Exception ex){ //exception was thrown, so there is no meshFilter found, carry on. Debug.Log(ex); } } int i = 0; foreach(MeshFilter filter in myMeshFilters){//setting values //meshManagers new MeshManager( filter, this, i); meshManagers.Add( new MeshManager( filter, this, i, myMeshManagerPropertiesi) ); i++; } if(meshManagers.Count() > 1){ //when there is only one mesh, there is no place for Inter-Branch connections ManageInterMeshConnections(2); } } private void Update(){ if( Input.GetKey(KeyCode.A) ){ meshManagers0.Aliases10.StartFire(); } if( Input.GetKey(KeyCode.B) ){ meshManagers0.TellAliasesToUpdate(); } } private void ManageInterMeshConnections(int NumberOfConnections){ /* NOthing*/ } private List FindNumberOfConnectionsOfAnMesh(int MeshNumber, int NumberOfLinksToFind){ /* */ } //parameters is Caller data public void StartFireOfVerticleInInterMeshConnection(int meshNumber, int AliasNumber){ foreach(PairOfAliasesFromDiffrentMeshes pair in FindPairsThatHaveAliasOfGivenData(meshNumber, AliasNumber) ){ meshManagerspair.MeshNumber1.Aliasespair.AliasNumber1.StartFire(); meshManagerspair.MeshNumber2.Aliasespair.AliasNumber2.StartFire(); //calling two Aliases is in fact not requaired as one of them are arleady under fire } } private List FindPairsThatHaveAliasOfGivenData(int meshNumber, int AliasNumber){ /* */ } public void StartFire( int AliasNumber, int MeshNumber){ meshManagersMeshNumber.AliasesAliasNumber.StartFire(); } } } Note that I will not describe inter-mesh connections in this part of tutorial General Fire Mesh Manager (GFMM) should be added as a script to each prefab that we want to be flamable. As later I want to add multithreading, and Unity Engine cant work on multiple threads, GFMM will work as an mediator between "damage" thread and Unity. All communication between MeshManagers and Unity will be passed through this class. (but this in later parts) List myMeshFilters = new List(); InterMeshPairsList = new List(); List myMeshManagerProperties = new List(); These are three global "containers" that will store the data. What are "MeshManagerProperties"? This is a structure defined in FideDamageStructures.cs MeshManagerProperties public struct MeshManagerProperties{ public float AliasHealthParameter; public float InflictDamageParameter; public float TryingToBeFiredParameter; public bool MakeMeshThick; } Stores some data about how the fire modeling should be done. Being a structure, it can be simply passed to MeshManager. Later, we will add more properties. Start method As GFMM inherits from MonoDevelop, this method will be called when game starts, without ingeration of programmer. This method has to: #Find FineDamagePropreties (FDP) in its "children" gameobjects. #Retrive its MeshFilter and Mesh properties (the latter stored as MeshManagerProperties structure) #Make a list of MeshManagers and assign MeshFilters and MeshProperties to them #Calculate Inter-Mesh connections (in next part). private void Start(){ List myMeshFilters = new List(); InterMeshPairsList = new List();//DONT WORRY, will be explained later List myMeshManagerProperties = new List(); myFireDamageProperties = GetComponentsInChildren() as FireDamageProperties[];// foreach(FireDamageProperties props in myFireDamageProperties){ try{// I am trying as there may be no meshFilter as a "siblins" of FDP. Somebody made an error and now a exception will be thrown MeshFilter CurrentFilter; CurrentFilter = props.ReturnMeshFilter(); myMeshFilters.Add(CurrentFilter); myMeshManagerProperties.Add( props.ReturnMeshManagerProperties() ); }catch(Exception ex){ //exception was thrown, so there is no meshFilter found, carry on. Debug.Log(ex); } } int i = 0; foreach(MeshFilter filter in myMeshFilters){//setting values meshManagers.Add( new MeshManager( filter, this, i, myMeshManagerPropertiesi) ); i++; } if(meshManagers.Count() > 1){ //when there is only one mesh, there is no place for Inter-Branch connections ManageInterMeshConnections(2); } } Okay, first some list are initialised , than we have myFireDamageProperties = GetComponentsInChildren() as FireDamageProperties[];// This is finding all FDP in object's children. I dont want to seek for meshFilters, as not every of them may be flamamble. "Flamambility" data is stored in FDP, as I stated before, so we have to first take care of them. We will get to this function later. foreach(FireDamageProperties props in myFireDamageProperties){ try{// I am trying as there may be no meshFilter as a "siblins" of FDP. Somebody made an error and now a exception will be thrown MeshFilter CurrentFilter; CurrentFilter = props.ReturnMeshFilter(); myMeshFilters.Add(CurrentFilter); myMeshManagerProperties.Add( props.ReturnMeshManagerProperties() ); }catch(Exception ex){ //exception was thrown, so there is no meshFilter found, carry on. Debug.Log(ex); } } This loop take care of checking if there is a "sibling" MeshFilter to FDP. You may be suprised that I used try and catch. First time I am using exceptions in these scripts!. Anyway, FDP will throw an exception in props.ReturnMeshFilter(); part, if it doesnt have any MeshFilters (see the appropiate paragraph for code). In that situation myMeshFilters.Add(CurrentFilter); myMeshManagerProperties.Add( props.ReturnMeshManagerProperties() ); lines will be omitted, which is loginal, as there is no mesh, so no flammable object. myMeshManagerProperties.Add( props.ReturnMeshManagerProperties() ); This code gets a Structure named MeshManagerProperties. Its variables were set in Inspector before game starts. Okay, now we have two lists: myMeshFilters and myMeshProperties. It is time to make MeshManagers. int i = 0; foreach(MeshFilter filter in myMeshFilters){//setting values meshManagers.Add( new MeshManager( filter, this, i, myMeshManagerPropertiesi) ); i++; } The constructor is a bit more complicated. #filter is of course coresponding MeshFilter. #this is GFDM that is "owner" of MeshMenager. (Similar to ownerManager in Verticles) #i Is a number of MeshManager (as we can have multiple MeshManagers in one GFDM) #myMeshManagerPropertiesi Appropiate structure of properties. Modifications To MeshManager public class MeshManager {//for each meshfilter there should be an distinct meshManager public int number; public GeneralFireDamageManager ownerManager;//Both like in Verticle! ... ... ... ... ... ... public MeshManager ( MeshFilter meshFilter, GeneralFireDamageManager XownerManager, int XNumber, MeshManagerProperties XProperties){//constructor ownerManager = XownerManager ; number = XNumber; AliasHealthParameter = XProperties.AliasHealthParameter;//setting the given parameters. InflictDamageParameter = XProperties.InflictDamageParameter; TryingToBeFiredParameter = XProperties.TryingToBeFiredParameter; IsMeshThick = XProperties.MakeMeshThick; Well, nothing special, just setting variables. FireDamageProperties class using UnityEngine; using System.Collections; using System; // For exception using RTS; /// /// A class which job is to hold properties set by map maker. /// It should be added to every mesh which should take part in fire damage. /// public class FireDamageProperties : MonoBehaviour{ public float AliasHealthParameter = 30f; public float InflictDamageParameter = 0.25f ; public float TryingToBeFiredParameter = 1f; public bool MakeMeshThick = true; MeshFilter[] filter; private void Awake(){ filter = GetComponentsInChildren(); } /// /// Returns a (sibling) mesh filter to the FireDamageProperties if found, throws System.NullReferenceException if not /// /// /// The mesh filter if it was found, a System.NullReferenceException; if not /// public MeshFilter ReturnMeshFilter(){ if(filter != null){//a MeshFilter was found! return filter0; }else{ throw new Exception("Filter not found"); } } public MeshManagerProperties ReturnMeshManagerProperties(){ MeshManagerProperties properties; properties.AliasHealthParameter = AliasHealthParameter; properties.InflictDamageParameter = InflictDamageParameter; properties.MakeMeshThick = MakeMeshThick; properties.TryingToBeFiredParameter = TryingToBeFiredParameter; return properties; } } Really, besides the exception, nothing special. Back to GeneralFireDamageMenager private void Update(){ if( Input.GetKey(KeyCode.A) ){ meshManagers0.Aliases10.StartFire(); } if( Input.GetKey(KeyCode.B) ){ meshManagers0.TellAliasesToUpdate(); } } Controling damage is transfered to GFDM, which I think is more appropiate. public void StartFire( int AliasNumber, int MeshNumber){ meshManagersMeshNumber.AliasesAliasNumber.StartFire(); } As now an Alias has 2 coordinates (Alias number and its Manager number), a new method is needed Ending Code, like before is in Github Repo, Version 10. Bear in mind, that there may be still some bugs. Category:C Sharp Category:Unity3D Category:Unity3D Building Damage Tutorial